package ms.maplestory.boot.service;

import ms.maplestory.boot.client.character.Char;
import ms.maplestory.boot.client.character.Inventory.Equip;
import ms.maplestory.boot.client.character.Inventory.Inventory;
import ms.maplestory.boot.client.character.Inventory.Item;
import ms.maplestory.boot.constants.ItemConstants;
import ms.maplestory.boot.enums.InventoryType;
import ms.maplestory.boot.loaders.ItemData;
import ms.maplestory.boot.loaders.container.ItemInfo;
import ms.maplestory.boot.repository.InventoryRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import ms.maplestory.boot.repository.ItemRepository;
import ms.maplestory.boot.service.helpers.InventoryHelper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

import static ms.maplestory.boot.enums.InventoryType.*;

@Slf4j
@Service
@RequiredArgsConstructor
public class InventoryService extends JpaService<Inventory, Integer> {

    private final InventoryRepository inventoryRepository;
    private final ItemRepository itemRepository;

    @Override
    public InventoryRepository getRepository() {
        return this.inventoryRepository;
    }

    @Transactional
    public void initForCreateChar(Char chr, int[] items) {
        for (int itemId : items) {
            Equip equip = ItemData.getEquipDeepCopyFromId(itemId, false);
            if (equip != null && ItemConstants.isEquip(itemId) && equip.getItemId() >= 1000000) {
                equip.setPosition(ItemConstants.getBodyPartFromItem(
                        equip.getItemId(), chr.getStat().getGender()));
                addItemToInventory(chr, Equipped, equip, true);
            }
        }
    }

    @Transactional
    public void addItemToInventory(Char chr, InventoryType type, Item item, boolean hasCorrectPosition) {
        if (item == null) {
            return;
        }
        Inventory inventory = InventoryHelper.getInventoryByType(chr, type);
        ItemInfo ii = ItemData.getItemInfoByID(item.getItemId());
        int quantity = item.getQuantity();
        if (inventory != null) {
            Item existingItem = InventoryHelper.getItemByItemIDAndStackable(inventory, item.getItemId());
            boolean rec = false;
            if (existingItem != null && existingItem.getInventoryType().isStackable() && existingItem.getQuantity() < ii.getSlotMax()) {
                if (quantity + existingItem.getQuantity() > ii.getSlotMax()) {
                    quantity = ii.getSlotMax() - existingItem.getQuantity();
                    item.setQuantity(item.getQuantity() - quantity);
                    rec = true;
                }
                existingItem.addQuantity(quantity);
//                chr.write(WvsContext.inventoryOperation(true, false,
//                        UpdateQuantity, (short) existingItem.getPosition(), (byte) -1, 0, existingItem));
                Item copy = item.deepCopy();
                copy.setQuantity(quantity);
                if (rec) {
                    addItemToInventory(chr, item.getInventoryType(), item, false);
                }
            } else {
                if (!hasCorrectPosition) {
                    item.setPosition(InventoryHelper.getFirstOpenSlot(inventory));
                }
                Item itemCopy = null;
                if (item.getInventoryType().isStackable() && ii != null && item.getQuantity() > ii.getSlotMax()) {
                    itemCopy = item.deepCopy();
                    quantity = quantity - ii.getSlotMax();
                    itemCopy.setQuantity(quantity);
                    item.setQuantity(ii.getSlotMax());
                    rec = true;
                }
                item.setInventoryId(inventory.getId());

                Item savedItem = this.addItem(inventory, item);

//                chr.write(WvsContext.inventoryOperation(true, false,
//                        Add, (short) item.getPosition(), (byte) -1, 0, savedItem));
                if (rec) {
                    addItemToInventory(chr, item.getInventoryType(), savedItem, false);
                }
            }
        }
    }

    private Item addItem(Inventory inventory, Item item) {
        Item savedItem = itemRepository.saveAndFlush(item);
        inventory.getItems().add(savedItem);
        return savedItem;
    }

}
